/**
 * HTTP请求工具 - 基于axios的二次封装
 */

import axios from 'axios';
import { LRUCache } from './request';

/**
 * HTTP状态码枚举
 */
export const HTTP_STATUS = {
  OK: 200,
  CREATED: 201,
  NO_CONTENT: 204,
  BAD_REQUEST: 400,
  UNAUTHORIZED: 401,
  FORBIDDEN: 403,
  NOT_FOUND: 404,
  METHOD_NOT_ALLOWED: 405,
  CONFLICT: 409,
  UNPROCESSABLE_ENTITY: 422,
  TOO_MANY_REQUESTS: 429,
  INTERNAL_SERVER_ERROR: 500,
  BAD_GATEWAY: 502,
  SERVICE_UNAVAILABLE: 503,
  GATEWAY_TIMEOUT: 504,
};

/**
 * 错误类型枚举
 */
export const ERROR_TYPES = {
  NETWORK_ERROR: 'NETWORK_ERROR',
  TIMEOUT_ERROR: 'TIMEOUT_ERROR',
  CANCEL_ERROR: 'CANCEL_ERROR',
  VALIDATION_ERROR: 'VALIDATION_ERROR',
  AUTH_ERROR: 'AUTH_ERROR',
  SERVER_ERROR: 'SERVER_ERROR',
  UNKNOWN_ERROR: 'UNKNOWN_ERROR',
};

/**
 * 请求配置类
 */
class HttpConfig {
  constructor() {
    this.baseURL = '';
    this.timeout = 10000;
    this.retryCount = 3;
    this.retryDelay = 1000;
    this.retryBackoff = 2;
    this.enableCache = false;
    this.cacheTimeout = 300000; // 5分钟
    this.enableDeduplication = true;
    this.enableLogging = true;
    this.enableProgress = false;
    this.headers = {
      'Content-Type': 'application/json',
    };
    this.interceptors = {
      request: [],
      response: [],
    };
    this.errorHandlers = new Map();
    this.authToken = null;
    this.refreshToken = null;
    this.refreshTokenUrl = null;
    this.isRefreshing = false;
    this.failedQueue = [];
  }

  /**
   * 设置基础URL
   * @param {string} baseURL - 基础URL
   */
  setBaseURL(baseURL) {
    this.baseURL = baseURL;
    return this;
  }

  /**
   * 设置超时时间
   * @param {number} timeout - 超时时间（毫秒）
   */
  setTimeout(timeout) {
    this.timeout = timeout;
    return this;
  }

  /**
   * 设置重试配置
   * @param {number} count - 重试次数
   * @param {number} delay - 重试延迟
   * @param {number} backoff - 退避倍数
   */
  setRetry(count, delay, backoff) {
    this.retryCount = count;
    this.retryDelay = delay;
    this.retryBackoff = backoff;
    return this;
  }

  /**
   * 设置缓存配置
   * @param {boolean} enable - 是否启用缓存
   * @param {number} timeout - 缓存超时时间
   */
  setCache(enable, timeout) {
    this.enableCache = enable;
    this.cacheTimeout = timeout;
    return this;
  }

  /**
   * 设置认证配置
   * @param {string} token - 认证token
   * @param {string} refreshToken - 刷新token
   * @param {string} refreshUrl - 刷新token的URL
   */
  setAuth(token, refreshToken, refreshUrl) {
    this.authToken = token;
    this.refreshToken = refreshToken;
    this.refreshTokenUrl = refreshUrl;
    return this;
  }

  /**
   * 添加请求拦截器
   * @param {Function} interceptor - 拦截器函数
   */
  addRequestInterceptor(interceptor) {
    this.interceptors.request.push(interceptor);
    return this;
  }

  /**
   * 添加响应拦截器
   * @param {Function} interceptor - 拦截器函数
   */
  addResponseInterceptor(interceptor) {
    this.interceptors.response.push(interceptor);
    return this;
  }

  /**
   * 添加错误处理器
   * @param {number} status - HTTP状态码
   * @param {Function} handler - 错误处理函数
   */
  addErrorHandler(status, handler) {
    this.errorHandlers.set(status, handler);
    return this;
  }
}

/**
 * HTTP请求类
 */
class HttpClient {
  constructor(config = new HttpConfig()) {
    this.config = config;
    this.instance = axios.create({
      baseURL: config.baseURL,
      timeout: config.timeout,
      headers: config.headers,
    });
    this.cache = new LRUCache(100);
    this.pendingRequests = new Map();
    this.setupInterceptors();
  }

  /**
   * 设置拦截器
   */
  setupInterceptors() {
    // 请求拦截器
    this.instance.interceptors.request.use(
      config => this.handleRequest(config),
      error => this.handleRequestError(error)
    );

    // 响应拦截器
    this.instance.interceptors.response.use(
      response => this.handleResponse(response),
      error => this.handleResponseError(error)
    );
  }

  /**
   * 处理请求
   * @param {Object} config - 请求配置
   * @returns {Object} 处理后的配置
   */
  handleRequest(config) {
    // 添加时间戳防止缓存
    if (config.method === 'get' && !config.params) {
      config.params = {};
    }
    if (config.method === 'get') {
      config.params._t = Date.now();
    }

    // 添加认证token
    if (this.config.authToken) {
      config.headers.Authorization = `Bearer ${this.config.authToken}`;
    }

    // 添加请求ID用于去重
    if (this.config.enableDeduplication) {
      const requestKey = this.generateRequestKey(config);
      config.requestKey = requestKey;
    }

    // 执行自定义请求拦截器
    this.config.interceptors.request.forEach(interceptor => {
      config = interceptor(config) || config;
    });

    // 记录请求日志
    if (this.config.enableLogging) {
      console.log(
        `[HTTP Request] ${config.method?.toUpperCase()} ${config.url}`,
        {
          params: config.params,
          data: config.data,
          headers: config.headers,
        }
      );
    }

    return config;
  }

  /**
   * 处理请求错误
   * @param {Error} error - 请求错误
   * @returns {Promise} 拒绝的Promise
   */
  handleRequestError(error) {
    if (this.config.enableLogging) {
      console.error('[HTTP Request Error]', error);
    }
    return Promise.reject(this.createError(error, ERROR_TYPES.NETWORK_ERROR));
  }

  /**
   * 处理响应
   * @param {Object} response - 响应对象
   * @returns {Object} 处理后的响应
   */
  handleResponse(response) {
    // 缓存GET请求的响应
    if (this.config.enableCache && response.config.method === 'get') {
      const cacheKey = this.generateRequestKey(response.config);
      this.cache.set(cacheKey, {
        data: response.data,
        timestamp: Date.now(),
      });
    }

    // 执行自定义响应拦截器
    let processedResponse = response;
    this.config.interceptors.response.forEach(interceptor => {
      processedResponse = interceptor(processedResponse) || processedResponse;
    });

    // 记录响应日志
    if (this.config.enableLogging) {
      console.log(
        `[HTTP Response] ${response.config.method?.toUpperCase()} ${response.config.url}`,
        {
          status: response.status,
          data: response.data,
        }
      );
    }

    return processedResponse;
  }

  /**
   * 处理响应错误
   * @param {Error} error - 响应错误
   * @returns {Promise} 拒绝的Promise
   */
  async handleResponseError(error) {
    const { response, request, code, config } = error;

    // 记录错误日志
    if (this.config.enableLogging) {
      console.error('[HTTP Response Error]', {
        status: response?.status,
        statusText: response?.statusText,
        data: response?.data,
        code,
        message: error.message,
      });
    }

    // 处理取消请求
    if (axios.isCancel(error)) {
      return Promise.reject(this.createError(error, ERROR_TYPES.CANCEL_ERROR));
    }

    // 处理网络错误
    if (!response) {
      return Promise.reject(this.createError(error, ERROR_TYPES.NETWORK_ERROR));
    }

    // 处理超时错误
    if (code === 'ECONNABORTED') {
      return Promise.reject(this.createError(error, ERROR_TYPES.TIMEOUT_ERROR));
    }

    // 处理认证错误
    if (response.status === HTTP_STATUS.UNAUTHORIZED) {
      return this.handleAuthError(error);
    }

    // 处理其他HTTP错误
    const errorType = this.getErrorType(response.status);
    const httpError = this.createError(error, errorType, response);

    // 执行自定义错误处理器
    const customHandler = this.config.errorHandlers.get(response.status);
    if (customHandler) {
      try {
        await customHandler(httpError, response);
      } catch (handlerError) {
        console.error('[Error Handler Error]', handlerError);
      }
    }

    return Promise.reject(httpError);
  }

  /**
   * 处理认证错误
   * @param {Error} error - 认证错误
   * @returns {Promise} 处理结果
   */
  async handleAuthError(error) {
    const { config } = error;

    // 如果正在刷新token，将请求加入队列
    if (this.config.isRefreshing) {
      return new Promise((resolve, reject) => {
        this.config.failedQueue.push({ resolve, reject });
      }).then(() => {
        return this.instance(config);
      });
    }

    // 如果没有刷新token配置，直接返回错误
    if (!this.config.refreshToken || !this.config.refreshTokenUrl) {
      return Promise.reject(this.createError(error, ERROR_TYPES.AUTH_ERROR));
    }

    this.config.isRefreshing = true;

    try {
      // 刷新token
      const response = await axios.post(this.config.refreshTokenUrl, {
        refreshToken: this.config.refreshToken,
      });

      const { token } = response.data;
      this.config.authToken = token;

      // 处理队列中的请求
      this.config.failedQueue.forEach(({ resolve }) => {
        resolve();
      });
      this.config.failedQueue = [];

      // 重试原请求
      config.headers.Authorization = `Bearer ${token}`;
      return this.instance(config);
    } catch (refreshError) {
      // 刷新失败，清空队列
      this.config.failedQueue.forEach(({ reject }) => {
        reject(refreshError);
      });
      this.config.failedQueue = [];
      return Promise.reject(
        this.createError(refreshError, ERROR_TYPES.AUTH_ERROR)
      );
    } finally {
      this.config.isRefreshing = false;
    }
  }

  /**
   * 生成请求唯一标识
   * @param {Object} config - 请求配置
   * @returns {string} 请求标识
   */
  generateRequestKey(config) {
    const { method, url, params, data } = config;
    return `${method}:${url}:${JSON.stringify(params || {})}:${JSON.stringify(data || {})}`;
  }

  /**
   * 获取错误类型
   * @param {number} status - HTTP状态码
   * @returns {string} 错误类型
   */
  getErrorType(status) {
    if (status >= 400 && status < 500) {
      if (status === 401) {
        return ERROR_TYPES.AUTH_ERROR;
      }
      if (status === 422) {
        return ERROR_TYPES.VALIDATION_ERROR;
      }
      return ERROR_TYPES.CLIENT_ERROR;
    }
    if (status >= 500) {
      return ERROR_TYPES.SERVER_ERROR;
    }
    return ERROR_TYPES.UNKNOWN_ERROR;
  }

  /**
   * 创建错误对象
   * @param {Error} error - 原始错误
   * @param {string} type - 错误类型
   * @param {Object} response - 响应对象
   * @returns {Object} 错误对象
   */
  createError(error, type, response = null) {
    return {
      type,
      message: error.message,
      code: error.code,
      status: response?.status,
      statusText: response?.statusText,
      data: response?.data,
      config: error.config,
      originalError: error,
      timestamp: new Date().toISOString(),
    };
  }

  /**
   * 检查缓存
   * @param {Object} config - 请求配置
   * @returns {any} 缓存数据
   */
  checkCache(config) {
    if (!this.config.enableCache || config.method !== 'get') {
      return null;
    }

    const cacheKey = this.generateRequestKey(config);
    const cached = this.cache.get(cacheKey);

    if (cached && Date.now() - cached.timestamp < this.config.cacheTimeout) {
      return cached.data;
    }

    return null;
  }

  /**
   * 检查重复请求
   * @param {Object} config - 请求配置
   * @returns {Promise} 重复请求的Promise或null
   */
  checkDuplicateRequest(config) {
    if (!this.config.enableDeduplication || !config.requestKey) {
      return null;
    }

    return this.pendingRequests.get(config.requestKey);
  }

  /**
   * 添加待处理请求
   * @param {Object} config - 请求配置
   * @param {Promise} promise - 请求Promise
   */
  addPendingRequest(config, promise) {
    if (config.requestKey) {
      this.pendingRequests.set(config.requestKey, promise);
    }
  }

  /**
   * 移除待处理请求
   * @param {Object} config - 请求配置
   */
  removePendingRequest(config) {
    if (config.requestKey) {
      this.pendingRequests.delete(config.requestKey);
    }
  }

  /**
   * 重试请求
   * @param {Object} config - 请求配置
   * @param {number} retryCount - 当前重试次数
   * @returns {Promise} 重试结果
   */
  async retryRequest(config, retryCount = 0) {
    if (retryCount >= this.config.retryCount) {
      throw new Error('Max retry attempts reached');
    }

    const delay =
      this.config.retryDelay * Math.pow(this.config.retryBackoff, retryCount);
    await new Promise(resolve => setTimeout(resolve, delay));

    return this.instance(config);
  }

  /**
   * 通用请求方法
   * @param {Object} config - 请求配置
   * @returns {Promise} 请求结果
   */
  async request(config) {
    // 检查缓存
    const cached = this.checkCache(config);
    if (cached) {
      return { data: cached, fromCache: true };
    }

    // 检查重复请求
    const duplicateRequest = this.checkDuplicateRequest(config);
    if (duplicateRequest) {
      return duplicateRequest;
    }

    // 创建请求Promise
    const requestPromise = this.executeRequest(config);
    this.addPendingRequest(config, requestPromise);

    try {
      const result = await requestPromise;
      return result;
    } finally {
      this.removePendingRequest(config);
    }
  }

  /**
   * 执行请求
   * @param {Object} config - 请求配置
   * @returns {Promise} 请求结果
   */
  async executeRequest(config) {
    try {
      return await this.instance(config);
    } catch (error) {
      // 检查是否需要重试
      if (this.shouldRetry(error)) {
        const retryCount = config.retryCount || 0;
        config.retryCount = retryCount + 1;
        return this.retryRequest(config, retryCount);
      }
      throw error;
    }
  }

  /**
   * 判断是否需要重试
   * @param {Error} error - 错误对象
   * @returns {boolean} 是否需要重试
   */
  shouldRetry(error) {
    if (!error.response) {
      return true;
    } // 网络错误重试
    const status = error.response.status;
    return status >= 500 || status === 429; // 服务器错误或限流重试
  }

  /**
   * GET请求
   * @param {string} url - 请求URL
   * @param {Object} params - 查询参数
   * @param {Object} config - 请求配置
   * @returns {Promise} 请求结果
   */
  get(url, params = {}, config = {}) {
    return this.request({
      method: 'get',
      url,
      params,
      ...config,
    });
  }

  /**
   * POST请求
   * @param {string} url - 请求URL
   * @param {any} data - 请求数据
   * @param {Object} config - 请求配置
   * @returns {Promise} 请求结果
   */
  post(url, data = {}, config = {}) {
    return this.request({
      method: 'post',
      url,
      data,
      ...config,
    });
  }

  /**
   * PUT请求
   * @param {string} url - 请求URL
   * @param {any} data - 请求数据
   * @param {Object} config - 请求配置
   * @returns {Promise} 请求结果
   */
  put(url, data = {}, config = {}) {
    return this.request({
      method: 'put',
      url,
      data,
      ...config,
    });
  }

  /**
   * PATCH请求
   * @param {string} url - 请求URL
   * @param {any} data - 请求数据
   * @param {Object} config - 请求配置
   * @returns {Promise} 请求结果
   */
  patch(url, data = {}, config = {}) {
    return this.request({
      method: 'patch',
      url,
      data,
      ...config,
    });
  }

  /**
   * DELETE请求
   * @param {string} url - 请求URL
   * @param {Object} config - 请求配置
   * @returns {Promise} 请求结果
   */
  delete(url, config = {}) {
    return this.request({
      method: 'delete',
      url,
      ...config,
    });
  }

  /**
   * 上传文件
   * @param {string} url - 请求URL
   * @param {FormData} formData - 表单数据
   * @param {Object} config - 请求配置
   * @returns {Promise} 请求结果
   */
  upload(url, formData, config = {}) {
    return this.request({
      method: 'post',
      url,
      data: formData,
      headers: {
        'Content-Type': 'multipart/form-data',
      },
      onUploadProgress: progressEvent => {
        if (config.onProgress) {
          const percentCompleted = Math.round(
            (progressEvent.loaded * 100) / progressEvent.total
          );
          config.onProgress(percentCompleted, progressEvent);
        }
      },
      ...config,
    });
  }

  /**
   * 下载文件
   * @param {string} url - 请求URL
   * @param {Object} config - 请求配置
   * @returns {Promise} 请求结果
   */
  download(url, config = {}) {
    return this.request({
      method: 'get',
      url,
      responseType: 'blob',
      onDownloadProgress: progressEvent => {
        if (config.onProgress) {
          const percentCompleted = Math.round(
            (progressEvent.loaded * 100) / progressEvent.total
          );
          config.onProgress(percentCompleted, progressEvent);
        }
      },
      ...config,
    });
  }

  /**
   * 批量请求
   * @param {Array} requests - 请求数组
   * @param {Object} options - 选项
   * @returns {Promise} 请求结果
   */
  async batch(requests, options = {}) {
    const { concurrency = 5, failFast = false } = options;
    const results = [];
    const errors = [];

    const executeBatch = async batch => {
      const promises = batch.map(async (request, index) => {
        try {
          const result = await this.request(request);
          results[index] = { success: true, data: result };
          return result;
        } catch (error) {
          results[index] = { success: false, error };
          errors.push(error);
          if (failFast) {
            throw error;
          }
        }
      });

      await Promise.all(promises);
    };

    // 分批执行
    for (let i = 0; i < requests.length; i += concurrency) {
      const batch = requests.slice(i, i + concurrency);
      await executeBatch(batch);
    }

    return {
      results,
      errors,
      successCount: results.filter(r => r.success).length,
      errorCount: errors.length,
    };
  }

  /**
   * 取消所有请求
   */
  cancelAll() {
    this.pendingRequests.clear();
  }

  /**
   * 清空缓存
   */
  clearCache() {
    this.cache.clear();
  }

  /**
   * 获取配置
   * @returns {HttpConfig} 配置对象
   */
  getConfig() {
    return this.config;
  }

  /**
   * 更新配置
   * @param {Object} newConfig - 新配置
   */
  updateConfig(newConfig) {
    Object.assign(this.config, newConfig);
    this.instance.defaults.baseURL = this.config.baseURL;
    this.instance.defaults.timeout = this.config.timeout;
    Object.assign(this.instance.defaults.headers, this.config.headers);
  }

  /**
   * 添加请求头
   * @param {string|Object} key - 请求头键名或请求头对象
   * @param {string} value - 请求头值（当key为字符串时）
   * @returns {HttpClient} 返回当前实例以支持链式调用
   */
  setHeader(key, value) {
    if (typeof key === 'object') {
      // 批量设置请求头
      Object.assign(this.instance.defaults.headers.common, key);
    } else {
      // 设置单个请求头
      this.instance.defaults.headers.common[key] = value;
    }
    return this;
  }

  /**
   * 删除请求头
   * @param {string|Array} key - 请求头键名或键名数组
   * @returns {HttpClient} 返回当前实例以支持链式调用
   */
  removeHeader(key) {
    if (Array.isArray(key)) {
      // 批量删除请求头
      key.forEach(k => {
        delete this.instance.defaults.headers.common[k];
      });
    } else {
      // 删除单个请求头
      delete this.instance.defaults.headers.common[key];
    }
    return this;
  }

  /**
   * 获取请求头
   * @param {string} key - 请求头键名（可选）
   * @returns {string|Object} 请求头值或所有请求头
   */
  getHeader(key) {
    if (key) {
      return this.instance.defaults.headers.common[key];
    }
    return { ...this.instance.defaults.headers.common };
  }

  /**
   * 清空所有请求头
   * @returns {HttpClient} 返回当前实例以支持链式调用
   */
  clearHeaders() {
    this.instance.defaults.headers.common = {};
    return this;
  }

  /**
   * 设置认证头
   * @param {string} token - 认证token
   * @param {string} type - 认证类型，默认为'Bearer'
   * @returns {HttpClient} 返回当前实例以支持链式调用
   */
  setAuthHeader(token, type = 'Bearer') {
    this.setHeader('Authorization', `${type} ${token}`);
    return this;
  }

  /**
   * 设置内容类型
   * @param {string} contentType - 内容类型
   * @returns {HttpClient} 返回当前实例以支持链式调用
   */
  setContentType(contentType) {
    this.setHeader('Content-Type', contentType);
    return this;
  }

  /**
   * 设置用户代理
   * @param {string} userAgent - 用户代理字符串
   * @returns {HttpClient} 返回当前实例以支持链式调用
   */
  setUserAgent(userAgent) {
    this.setHeader('User-Agent', userAgent);
    return this;
  }

  /**
   * 设置自定义请求头（仅对单次请求有效）
   * @param {Object} headers - 请求头对象
   * @returns {Function} 返回一个函数，用于在请求时应用这些请求头
   */
  withHeaders(headers) {
    return config => {
      config.headers = { ...config.headers, ...headers };
      return config;
    };
  }
}

/**
 * 创建HTTP客户端
 * @param {HttpConfig|Object} config - 配置对象
 * @returns {HttpClient} HTTP客户端实例
 */
export function createHttpClient(config = {}) {
  const httpConfig = config instanceof HttpConfig ? config : new HttpConfig();
  if (typeof config === 'object') {
    Object.assign(httpConfig, config);
  }
  return new HttpClient(httpConfig);
}

/**
 * 创建默认HTTP客户端
 * @returns {HttpClient} 默认HTTP客户端实例
 */
export function createDefaultHttpClient() {
  // 在浏览器环境中安全地获取环境变量
  const getEnvVar = (key, defaultValue = '') => {
    // 尝试从window对象获取（如果存在）
    if (typeof window !== 'undefined' && window.VUE_APP_API_BASE_URL) {
      return window.VUE_APP_API_BASE_URL;
    }
    return defaultValue;
  };

  const config = new HttpConfig()
    .setBaseURL(getEnvVar('VUE_APP_API_BASE_URL', ''))
    .setTimeout(10000)
    .setRetry(3, 1000, 2)
    .setCache(true, 300000)
    .addErrorHandler(HTTP_STATUS.UNAUTHORIZED, error => {
      // 处理401错误，跳转到登录页
      if (typeof window !== 'undefined') {
        window.location.href = '/login';
      }
    })
    .addErrorHandler(HTTP_STATUS.FORBIDDEN, error => {
      // 处理403错误
      console.error('Access denied:', error);
    })
    .addErrorHandler(HTTP_STATUS.NOT_FOUND, error => {
      // 处理404错误
      console.error('Resource not found:', error);
    })
    .addErrorHandler(HTTP_STATUS.INTERNAL_SERVER_ERROR, error => {
      // 处理500错误
      console.error('Internal server error:', error);
    });

  return new HttpClient(config);
}

// 导出默认实例
export const httpClient = createDefaultHttpClient();

// 导出类和枚举
export { HttpConfig, HttpClient };
